package org.levi.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import org.levi.core.JSONSerializer;
import org.levi.core.RpcEncoder;
import org.levi.core.RpcRequest;
import org.levi.service.HelloService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RPCConsumer {

    private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public static HelloServiceHandler helloServiceHandler;

    public static RpcRequest rpcRequest;

    public static void initClient() throws InterruptedException {

        helloServiceHandler = new HelloServiceHandler();
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) {
                            socketChannel.pipeline().addFirst(new RpcEncoder(RpcRequest.class, new JSONSerializer()),
                                    new StringDecoder(),
                                    helloServiceHandler);
                        }
                    });
            bootstrap.connect("127.0.0.1", 8889).sync();
        } finally {
            //workGroup.shutdownGracefully();
        }
    }

    public static Object createProxy(Class<?> serviceClass) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{serviceClass}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                if (helloServiceHandler == null) {
                    initClient();
                }
                if (rpcRequest == null) {
                    rpcRequest = new RpcRequest();
                    rpcRequest.setClassName(HelloService.class.getName());
                    rpcRequest.setMethodName("sayHello");
                    rpcRequest.setParameters(new String[]{"levi"});
                    rpcRequest.setParameterType(new Class[]{String.class});
                }
                helloServiceHandler.setRpcRequest(rpcRequest);
                Object result = executorService.submit(helloServiceHandler).get();
                System.out.println("invoke " + result);
                return result;
            }
        });
    }
}
